#include"event_loop.h"
#include <assert.h>

//构造，初始化epoll堆
event_loop::event_loop(){
    //创建epoll句柄
    _epfd = epoll_create1(0);    //flag=0 等价于epll_craete(最大值)
    if (_epfd == -1) {
        fprintf(stderr, "epoll_create error\n");
        exit(1);
    }
}

//阻塞循环处理事件,处理eopll_wait，并调用对应的回调函数
void event_loop::event_process(){
    io_event_map_it ev_it;
    //要处理的并非一定是只有一个fd
    while(true){
        
        int nfds = epoll_wait(_epfd, _fired_evs, MAXEVENTS, -1);
        
        for(int i=0; i < nfds; i++){
            
            //通过触发的fd找到对应的绑定事件
            ev_it = _io_evs.find(_fired_evs[i].data.fd);
            assert(ev_it != _io_evs.end());
            io_event *ev = &(ev_it->second);

            if (_fired_evs[i].events & EPOLLIN) {
                //读事件，调读回调函数
                void *args = ev->rcb_args;
                ev->read_callback(this, _fired_evs[i].data.fd, args);
            }
            else if (_fired_evs[i].events & EPOLLOUT) {
                //写事件，调写回调函数
                void *args = ev->wcb_args; 
                ev->write_callback(this, _fired_evs[i].data.fd, args);
            }
            else if (_fired_evs[i].events &(EPOLLHUP|EPOLLERR)) {
                //水平触发未处理，可能会出现HUP事件，正常处理读写，没有则清空
                if (ev->read_callback != NULL) {
                    void *args = ev->rcb_args;
                    ev->read_callback(this, _fired_evs[i].data.fd, args);
                }
                else if (ev->write_callback != NULL) {
                    void *args = ev->wcb_args;
                    ev->write_callback(this, _fired_evs[i].data.fd, args);
                }
                else {
                    //删除
                    fprintf(stderr, "fd %d get error, delete it from epoll\n", _fired_evs[i].data.fd);
                    this->del_io_event(_fired_evs[i].data.fd);
                }
            }
        }

        // 执行完所有的读写任务后，执行其他的已经就绪的任务
        this->execute_ready_tasks();
    }
}

// 这里我们处理的事件机制是
// 如果EPOLLIN 在mask中， EPOLLOUT就不允许在mask中
// 如果EPOLLOUT 在mask中， EPOLLIN就不允许在mask中
// 如果想注册EPOLLIN|EPOLLOUT的事件， 那么就调用add_io_event() 方法两次来注册。

//添加一个io事件到loop中
void event_loop::add_io_event(int fd, io_callback *proc, int mask, void *args){
    int final_mask;
    int op;
    
    // 1.找到当前的fd是否已经是已有事件
    io_event_map_it it = _io_evs.find(fd);
    
    // 如果没有事件存在，ADD方式添加到epoll中
    if (it == _io_evs.end()) {  
        final_mask = mask;    
        op = EPOLL_CTL_ADD;
    }
    else{   // 如果事件不存在，MOD方式修改到epoll中
        final_mask = it->second.mask | mask;
        op = EPOLL_CTL_MOD;
    }
    _io_evs[fd].mask = final_mask;

    // 2.将fd和 io_callback绑定在map中
    if (mask & EPOLLIN) {
        //读事件回调函数注册
        _io_evs[fd].read_callback = proc;
        _io_evs[fd].rcb_args = args;
    }
    else if (mask & EPOLLOUT) {
        _io_evs[fd].write_callback = proc;
        _io_evs[fd].wcb_args = args;
    }

    // 3.将当前事件加入到原生的epoll句柄中
    struct epoll_event event;
    event.events = final_mask;
    event.data.fd = fd;
    if (epoll_ctl(_epfd, op, fd, &event) == -1) {
        fprintf(stderr, "epoll ctl %d error\n", fd);
        return;
    }

    // 4.将当前fd加入到正在监听的fd集合中
    listen_fds.insert(fd);
}

//删除一个io事件从loop中
void event_loop::del_io_event(int fd){
    //如果没有该事件，直接返回
    io_event_map_it it = _io_evs.find(fd);
    if (it == _io_evs.end()) {
        return ;
    }
    //将事件从_io_evs删除
    _io_evs.erase(fd);

    //将fd从监听集合中删除
    listen_fds.erase(fd);

    //将fd从epoll堆删除
    epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL);
}

//删除一个io事件的EPOLLIN/EPOLLOUT
void event_loop::del_io_event(int fd, int mask){
    //如果没有该事件，直接返回
    io_event_map_it it = _io_evs.find(fd);
    if (it == _io_evs.end()) {
        return ;
    }

    int &o_mask = it->second.mask;
    //修正mask
    o_mask = o_mask & (~mask);
    
    if (o_mask == 0) {  
        //如果修正之后 mask为0，则删除
        this->del_io_event(fd);
    }
    else {  
        //如果修正之后，mask非0，则修改
        struct epoll_event event;
        event.events = o_mask;
        event.data.fd = fd;
        epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &event);
    }
}



// 添加task到_ready_tasks的方法
void event_loop::add_task(task_func func, void* args){
    task_func_pair func_pair(func, args);
    
    _ready_tasks.push_back(func_pair);
}

// 执行_ready_tasks中全部任务的方法
void event_loop::execute_ready_tasks(){
    std::vector<task_func_pair>::iterator it;
    for(it=_ready_tasks.begin(); it!=_ready_tasks.end(); it++){
        // 取出任务的执行函数
        task_func func = it->first;
        // 取出执行函数的参数
        void * args = it->second;
        // 调用任务函数
        func(this, args);
    }

    // 全部函数执行完毕后，清空_ready_tasks任务
    _ready_tasks.clear();
}

// 得到目前在线的fd都有哪些
void event_loop::get_fds(listen_fd_set &fds){
    fds = listen_fds;
}